#include <iostream>
#include <stdlib.h>
#include <fstream>
#include <string>
#include <iomanip>
#include <locale>
#include <sstream>
#include <assert.h>
#include <vector>
#include <map>
using namespace std;

#define MAX_DAYS  200
#define MAX_STOCKS 2000
#define MAX_FAILURES 10

class stock_stat {
    public:
        // From the table
        double open, close, high, low, fsto_k, ssto_k, ssto_d;

        //derived
        double hh, ll, sma50, sma200, ema, ema12, ema26, macd, ema9_macd, rsi;

        stock_stat(){
           open = close = high = low = ssto_k = ssto_d = 0.0; 
           fsto_k = hh = ll = ema = ema12 = ema26 = macd = ema9_macd = 0.0;
        }

        ~stock_stat()
        { }
};

class stock{
    public:
        stock_stat sstat[MAX_DAYS];
        // stock name
        string name;


        // calculate relative strength index
        void rsi(int days)
        {
            int i, j;
            for (j = 1; j < MAX_DAYS - days - 2; j++) {
                // variables to keep the sum of up and down days
                double up_days_diff = 0, down_days_diff = 0;
                for (i = j; i < days + j ; i++) {
                    if (sstat[i].close < sstat[i + 1].close)
                        down_days_diff += sstat[i + 1].close - sstat[i].close;
                    else
                        up_days_diff += sstat[i].close - sstat[i + 1].close;
                }

                double rs = up_days_diff / down_days_diff;

                sstat[j].rsi = 100 - 100 / (1 + rs);    


            }
        }

        void ssto(int days)
        {
            int i;

            // First calculate the highest highs and lowest lows
            for (i = MAX_DAYS - days - 1; i > 0; i--) {
                sstat[i].hh = find_highest_high(i, days);
                sstat[i].ll = find_lowest_low(i, days);
                sstat[i].fsto_k = ((sstat[i].close - sstat[i].ll) /
                        (sstat[i].hh - sstat[i].ll)) * 100; 
               
                // ugly but prevents multiple loops 
                if (i < MAX_DAYS - days - 4)
                    sstat[i].ssto_k = (sstat[i + 1].fsto_k + sstat[i +
                            2].fsto_k + sstat[i + 3].fsto_k) / 3;

                if (i < MAX_DAYS - days - 7)
                    sstat[i].ssto_d = (sstat[i + 1].ssto_k + sstat[i +
                            2].ssto_k + sstat[i + 3].ssto_k) / 3;
                
            }
        }

        void calc_macd()
        {
            sstat[MAX_DAYS - 1].ema12 = sstat[MAX_DAYS - 1].close;
            sstat[MAX_DAYS - 1].ema26 = sstat[MAX_DAYS - 1].close;

            int i;
            double alpha12 = .15;
            double alpha26 = .075;
            double alpha9 = .2;
            for(i = MAX_DAYS - 2; i > 0; i--) {
                sstat[i].ema12 = 0.15 * sstat[i].close + 0.85 * sstat[i +
                    1].ema12;
                sstat[i].ema26 = 0.075 * sstat[i].close + .925 * sstat[i +
                    1].ema26;
                sstat[i].macd = sstat[i].ema12 - sstat[i].ema26;
                sstat[i].ema9_macd = 0.2 * sstat[i].macd + 0.8 * sstat[i +
                    1].ema9_macd;
                //cout << "macd " << sstat[i].macd << " " << sstat[i].ema9_macd << endl ;
            }
        }

        void ema(int days)
        {
            int i;
            if (!days)
                return;
            
            // boundary condition
            sstat[MAX_DAYS - 1].ema = sstat[MAX_DAYS - 1].close;

            double alpha = 2 / (days + 1);
            for(i = MAX_DAYS - 2; i >=0; i--)
                sstat[i].ema = alpha * sstat[i].close + (1 - alpha) *
                    sstat[i + 1].ema;

        }

        void print_stats()
        {
            cout << name << "\t"<< sstat[1].ssto_k << "\t " <<
                sstat[1].ssto_d << "\t " << sstat[1].ema << "\t" <<
                sstat[1].macd << "\t" << sstat[1].ema9_macd << 
                "\t" << sstat[1].rsi << endl;

        }
    private:
        double find_highest_high(int index, int days)
        {
            int i;
            double local_hh = sstat[index].high;
            for (i = index + 1; i < index + days; i++)
                if (sstat[i].high > local_hh) {
                    local_hh = sstat[i].high;
                }
            return local_hh;
        }
        
        double find_lowest_low(int index, int days)
        {
            int i;
            double local_ll = sstat[index].low;
            for (i = index + 1; i < index + days; i++)
                if (sstat[i].low < local_ll) {
                    local_ll = sstat[i].low;
                }
            return local_ll;
        }
};

stock *st;

int main(int argc, char **argv)
{
    st = new stock[MAX_STOCKS];
    int st_count = 0;

    ifstream stocks_name_file;
    stocks_name_file.open("call_list.txt");
    string stock_name_line;

    while(stocks_name_file.good()) {
        getline(stocks_name_file, stock_name_line);
        string a = "\"" + stock_name_line +"\"";
        string c = "curl \"http://ichart.finance.yahoo.com/table.csv?d=12&e=31&f=2013&g=d&a=2&b=2&c=2012&ignore=.csv&s="+a+"\" | tee ./hist_data/"+a+".csv";
        const char *d = c.c_str();

        // Save the name of the stock
        st[st_count].name = a;

        //Now make sense out of the data 
        ifstream myfile;

        a = "./hist_data/"+stock_name_line+".csv";
        const char *c_file = a.c_str();
        myfile.open(c_file);

        // Count the number of line

        int line_count = 0;
        // Run this while there are elements in the file
        while (myfile.good() && line_count < MAX_DAYS) {
            string line;
            getline(myfile, line);

            // Rotating position for the occurence of comma
            size_t found, loop_found;
            double result;

            // keep track of the attribute count
            int attr_count = 0;
            // Ignore the first attribute
            found = line.find_first_of(",");
            string num = line.substr(0, found);

            ++attr_count;
            // Convert the string to a number
            while(attr_count < 5) {
                loop_found = line.find_first_of(",", found + 1);
                num = line.substr(found + 1, loop_found);
                istringstream convert(num);
                if (!(convert >> result)) {
                    result = 0;
                }

                switch(attr_count) {
                case 1:
                    st[st_count].sstat[line_count].open = result;
                    break;
                case 2:
                    st[st_count].sstat[line_count].high = result;
                    break;
                case 3:
                    st[st_count].sstat[line_count].low = result;
                    break;
                case 4: 
                    st[st_count].sstat[line_count].close = result;
                    break;
                }
                found = loop_found;
                ++attr_count;
            }
            ++line_count;
        }
        // Close my file
        myfile.close(); 

        int i = st_count;
        if (st[i].sstat[1].open) {
            st[i].ssto(14);
            st[i].ema(22);
            st[i].calc_macd();
            st[i].rsi(10);
            if (st[i].sstat[1].rsi > 65) {
                st[i].print_stats();
            }
        }
        ++st_count;

    }

    // Now do the training
    stocks_name_file.close();

}
